package others;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.LongStream;

/**
 * 1.将大任务分解成小任务执行
 * 2.任务线程与任务队列一对一
 * 3.正常线程获取对应队列头部任务执行；任务窃取机制，双端队列；被窃取线程获取队列头部任务，窃取线程获取队列头部任务;
 * 4.RecursiveAction(无返回值)与RecursiveTask(有返回值)
 * 5.invokeAll等同于fork，网上说法是比fork更高效
 * 6.使用get方法执行任务时，当子任务出现异常时可以在main主线程中进行捕获 方法join遇到异常直接抛出
 * 7.构造方法可以传如异常处理机制(未测试)
 * 8.
 */
public class ForJoinPoolTest {
    public static void main(String[] args) throws InterruptedException {
        //1.初步了解RecursiveAction使用
//        recursiveAction();
        //2.初步了解与RecursiveTask使用
//        recursiveTask();
        //3.测试get与join区别
        ecpCatchAction();
        //TODO 4.构造方法异常处理机制
    }

    private static void recursiveAction() throws InterruptedException {
        Instant start = Instant.now();
        System.out.printf("当前系统可执行线程数:%d%n", Runtime.getRuntime().availableProcessors());

        // 创建线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        // 创建任务并提交
        forkJoinPool.submit(new MyRecursiveAction(1, 100));
        // 阻塞主线程，直到所有线程执行完成
        forkJoinPool.awaitTermination(2, TimeUnit.SECONDS);
        // 关闭线程
        forkJoinPool.shutdown();

        Instant end = Instant.now();
        System.out.printf("任务执行时间:%d%n", Duration.between(start, end).toMillis());
    }

    private static void recursiveTask() {
        Instant start = Instant.now();
        List<Integer> list = new ArrayList<>();
        System.out.printf("当前系统可执行线程数:%d%n", Runtime.getRuntime().availableProcessors());
        for (int i = 1; i < 101; i++) {
            list.add(i);
        }

        // 创建线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        // 创建任务并提交
        Integer result = forkJoinPool.invoke(new MyRecursiveTask(list, 0, 100));
        // 关闭线程数
        forkJoinPool.shutdown();
        System.out.printf("计算结果:%s%n", result);

        Instant end = Instant.now();
        System.out.printf("任务执行时间:%d%n", Duration.between(start, end).toMillis());
    }

    private static void ecpCatchAction() throws InterruptedException {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Void> submit = forkJoinPool.submit(new EcpRecursiveAction());
        try {
//            submit.get();
//            submit.join();
        } catch (Exception e) {
            //submit.get捕获到的异常本质还是ExecutionException，detailMessage为java.lang.RuntimeException: java.lang.RuntimeException: 自定义异常
            //submit.join()捕获到的异常就是RuntimeException本身
            //如果不调用get或join方法，则不会捕捉到异常
            System.out.printf("捕获到异常,且异常类型%s:%s%n", e.getClass(), e.getMessage());
        }
        // 阻塞等待任务执行完成
        forkJoinPool.awaitTermination(3, TimeUnit.SECONDS);
        // 关闭线程
        forkJoinPool.shutdown();
    }
}

class MyRecursiveAction extends RecursiveAction {
    public static final int MAX = 20;
    private int start;
    private int end;

    public MyRecursiveAction(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        if ((end - start) < MAX) {
            long result = LongStream.range(start, end).reduce(Long::sum).orElse(0L);
            System.out.printf("%d到%d 计算结果:%d %n", start, end, result);
        } else {
            System.out.println("=============分解任务=============");
            int middle = (end + start) / 2;
            MyRecursiveAction left = new MyRecursiveAction(start, middle);
            MyRecursiveAction right = new MyRecursiveAction(middle, end);
            //子任务拆分
            left.fork();
            right.fork();
        }
    }
}

class MyRecursiveTask extends RecursiveTask<Integer> {

    public static final int MAX = 20;

    private List<Integer> list;
    private int start;
    private int end;

    public MyRecursiveTask(List<Integer> list, int start, int end) {
        this.list = list;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if ((end - start) <= MAX) {
            int sum = 0;
            for (int i = start; i < end; i++) {
                sum += list.get(i);
            }
            return sum;
        } else {
            System.out.println("=============分解任务=============");
            int middle = (start + end) / 2;
            MyRecursiveTask left = new MyRecursiveTask(this.list, start, middle);
            MyRecursiveTask right = new MyRecursiveTask(this.list, middle, end);
            // 继续分解任务
//            left.fork();
//            right.fork();
            invokeAll(left, right);
            // 将left的子任务结果合并返回 + 将right的子任务结果合并返回
            return left.join() + right.join();
        }
    }
}

class EcpRecursiveAction extends RecursiveAction {

    @Override
    protected void compute() {
        System.out.println("执行EcpRecursiveAction任务");
        //测试能否被主线程catch
        throw new RuntimeException("自定义异常");
    }
}
